import { FastifyReply, FastifyRequest } from 'fastify';
import { Controller, GET, POST } from 'fastify-decorators';
import { z } from "zod";
import { app } from '..';
import emailService from '../service/email.service';
import googleService from '../service/google.service';
import { md5 } from '../utils/md5';
import { createCaptcha } from '../utils/captcha';
import userService from '../service/user.service';


@Controller({ route: '/auth' })
export default class AuthController {
    signUpSchema = z.object({
        email: z.string().email(),
        password: z.string().min(6),
        captcha: z.string().min(4),
    });

    signInByGoogleSchema = z.object({
        token: z.string().min(1),
    });

    @POST('/signIn')
    async signInHandle(request: FastifyRequest, reply: FastifyReply) {
        app.prisma.user.findFirst({ where: { id: 1 } });
        const { email, password } = userService.createUserSchema.parse(request.body);
        const user = await userService.query({ email, password: md5(password) });
        if (!user) {
            throw new Error('Invalid email or password');
        }

        const token = app.jwt.sign({ email, id: user.id });
        reply.setCookie('token', token, {
            path: '/',
            httpOnly: true,
            sameSite: 'none',
            secure: true,
            expires: new Date(Date.now() + 1000 * 3600 * 24 * 7),
        });

        return app.json({ ...user, token });
    }

    @POST('/signIn/google')
    async signInByGoogleHandle(request: FastifyRequest, reply: FastifyReply) {
        const { token } = this.signInByGoogleSchema.parse(request.body);
        const userInfo = await googleService.verifyToken(token);
        if (!userInfo) {
            throw new Error('Invalid token');
        }

        const { email, sub } = userInfo;
        if (!email) {
            throw new Error('Invalid email');
        }

        let user = await userService.query({ email, password: md5(sub) });
        if (!user) {
            user = await userService.create({ email, password: md5(sub) });
        }
        const sendToken = app.jwt.sign({ email, id: user.id });
        reply.setCookie('token', sendToken, {
            path: '/',
            httpOnly: true,
            sameSite: 'none',
            secure: true,
            expires: new Date(Date.now() + 1000 * 3600 * 24 * 7),
        });

        return app.json({ email, token });
    }

    @POST({ url: '/signOut' })
    async signOutHandle(request: FastifyRequest, reply: FastifyReply) {
        reply.clearCookie('token', {
            path: '/',
            sameSite: 'none',
            secure: true,
        });
        return app.json(null);
    }

    @GET('/captcha')
    async getCaptcha(request: FastifyRequest, reply: FastifyReply) {
        const { email } = z.object({ email: z.string().email() }).parse(request.query);
        const captcha = createCaptcha();

        await app.setCache('captcha', captcha, 1000 * 60 * 2, true);
        await emailService.sendCaptcha({ to: email, captcha });

        return app.json({ message: 'send email success' });
    }

    @POST('/signUp')
    async testHandle(request: FastifyRequest, reply: FastifyReply) {
        const { email, password, captcha } = this.signUpSchema.parse(request.body);

        const captchaCache = await app.getCache('captcha', true);
        if (captchaCache !== captcha) {
            throw new Error('Invalid captcha');
        }

        const user = await userService.create({ email, password: md5(password) });
        return app.json(user);
    }
}